    /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
 * @author caos
 */
public class ServerMediator extends Thread
{
    private Socket socket;
    private ServerReader sR;
    private ClientWriter cW;
    private SynchronousQueue<String> messages;
    private CryptHelper cHelper;
    private MessagesBuilderClient mBC;
    private final static String ip="80.180.25.137";
    private final static int port=25566;
    private boolean connected;
    private String userName;
    
    private static final ServerMediator INSTANCE = new ServerMediator();
    private ServerMediator() 
    {
        connected=false;
    }
    
    public static ServerMediator getInstance() {
        return INSTANCE;
    }
    
    private void startMediator()
    {
        sR.start();
        cW.start();
        start();
    }
    
    public String requireList()
    {
        cW.addInQueue(MessagesBuilderClient.Reqlist());
        return getMessageInQueue();
    }
    
    void disconnect()
    {
        try 
        {
            interrupt();
            sR.interrupt();
            cW.interrupt();
            socket.close();
            connected=false;
        } 
        catch (IOException ex) 
        {
            System.err.println("Error: " + ex.getMessage());
        }
        
    }
    
    void connectToServer() throws Exception
    {
        if(!connected)
        {
            socket=new Socket(ip, port);
            if(socket == null || !socket.isBound() )
                throw new Exception("Error while connecting to the server :'(");

            OutputStream oS=socket.getOutputStream();
            InputStream iS=socket.getInputStream();

            cHelper=new CryptHelper();
            
            while(iS.available()<1);
            
            int len=iS.available();
            System.out.println("Len: " + len);
            
            
            byte RSAPubRaw[]= new byte[len];
            
            for(int i=0; i < len; i++)
                RSAPubRaw[i] = (byte)iS.read();
            cHelper.setRemotePK(RSAPubRaw);
            
            System.out.println("Key len: " + cHelper.getAESLocal().length);
            oS.write(cHelper.getAESLocal());
            
            PrintStream pS=new PrintStream(oS);            
            BufferedReader bR=new BufferedReader(new InputStreamReader(iS));
            //TODO: aumentare la flessibilita'. flex++
            sR=new ServerReader(bR);       
            cW=new ClientWriter(pS); 
            mBC=new MessagesBuilderClient(cHelper);
            messages=new SynchronousQueue<String>();
            startMediator();
            connected=true;
        }
    }
    String getUsername()
    {
        return userName;
    }
    
    String doLogin(String userName, String password)
    {        
        this.userName=userName;
        cW.addInQueue(MessagesBuilderClient.LoginMessage(userName, password));
        return getMessageInQueue();
    }
    
    void doLogout()
    {        
        cW.addInQueue(MessagesBuilderClient.LogoutMessage());
    }
    
    String doRegistration(String userName, String password)
    {
        cW.addInQueue(mBC.RegistrationMessage(userName, password));
        return getMessageInQueue();
    }
    
    String getMessageInQueue()
    {
        try
        {
            return messages.poll(5000, TimeUnit.MILLISECONDS);
        } 
        catch (InterruptedException ex) 
        {
            try 
            {
                System.err.println("Server is not responding, trying to reconnect!");
                connected=false;
                connectToServer();
                return messages.poll(5000, TimeUnit.MILLISECONDS);
            } 
            catch (Exception ex1)
            {
                return null;
            }
        }
    }
    
    @Override
    public void run()
    {
        while(true)
        {
            String tmp=null;
            if((tmp=sR.pollQueue())!=null)
                messages.add(tmp);
        }
    }
}
